﻿#include "BasePass.h"

#include "../../../Common/Singleton.h"
#include "../CSFeatures/GPUWaves.h"
#include "../ResourceManager/Dx2RootSignatureManager.h"
#include "../ResourceManager/Dx2GeometryManager.h"
#include "../ResourceManager/Dx2MaterialManager.h"
#include "../ResourceManager/Dx2RootSignatureManager.h"
#include "../ResourceManager/Dx2ShaderAndLayoutManager.h"

BasePass::BasePass():
    Pass()
{
}

void BasePass::BuildRenderItems(
    std::vector<std::unique_ptr<RenderItem>>& allRitems,UINT& lastObjIndex)
{   
    auto gridRitem = std::make_unique<RenderItem>();
    gridRitem->World = MathHelper::Identity4x4();
    XMStoreFloat4x4(&gridRitem->TexTransform, XMMatrixScaling(5.0f, 5.0f, 1.0f));
    gridRitem->ObjCBIndex = lastObjIndex;
    lastObjIndex ++;
    gridRitem->Mat = Singleton<Dx2MaterialManager>::Instance()->GetMaterial("grass").get();
    gridRitem->Geo = Singleton<Dx2GeometryManager>::Instance()->GetGeometry("landGeo").get();
    gridRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
    gridRitem->IndexCount = gridRitem->Geo->DrawArgs["grid"].IndexCount;
    gridRitem->StartIndexLocation = gridRitem->Geo->DrawArgs["grid"].StartIndexLocation;
    gridRitem->BaseVertexLocation = gridRitem->Geo->DrawArgs["grid"].BaseVertexLocation;

   

    auto skullRitem = std::make_unique<RenderItem>();
    skullRitem->World = MathHelper::Identity4x4();

    skullRitem->ObjCBIndex = lastObjIndex;
    lastObjIndex ++;
    
    skullRitem->Mat = Singleton<Dx2MaterialManager>::Instance()->GetMaterial("skullMat").get();
    skullRitem->Geo = Singleton<Dx2GeometryManager>::Instance()->GetGeometry("skullGeo").get();
    skullRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
    skullRitem->IndexCount = skullRitem->Geo->DrawArgs["skull"].IndexCount;
    skullRitem->StartIndexLocation = skullRitem->Geo->DrawArgs["skull"].StartIndexLocation;
    skullRitem->BaseVertexLocation = skullRitem->Geo->DrawArgs["skull"].BaseVertexLocation;

    

    mSkullRitem = skullRitem.get();

    mRenderItems.push_back(gridRitem.get());
    mRenderItems.push_back(skullRitem.get());

    allRitems.push_back(std::move(gridRitem));
    allRitems.push_back(std::move(skullRitem));
}

void BasePass::BuildPSOs(
    ID3D12Device* device,
    DXGI_FORMAT BackBufferFormat,
    DXGI_FORMAT DepthStencilFormat,
    bool _4xMsaaState,
    UINT _4xMsaaQuality
    )
{
    D3D12_GRAPHICS_PIPELINE_STATE_DESC opaquePsoDesc;
    ZeroMemory(&opaquePsoDesc,sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));
	
    opaquePsoDesc.InputLayout = {Singleton<Dx2ShaderAndLayoutManager>::Instance()->GetInputLayout().data(),(UINT)Singleton<Dx2ShaderAndLayoutManager>::Instance()->GetInputLayout().size()};
    opaquePsoDesc.pRootSignature = Singleton<Dx2RootSignatureManager>::Instance()->GetRootSignature(RootSignatureType::Default).Get();
	
    opaquePsoDesc.VS =
        {
        reinterpret_cast<BYTE*>(Singleton<Dx2ShaderAndLayoutManager>::Instance()->GetShader("standardVS")->GetBufferPointer()),
        Singleton<Dx2ShaderAndLayoutManager>::Instance()->GetShader("standardVS")->GetBufferSize()
    };
	
    opaquePsoDesc.PS =
        {
        reinterpret_cast<BYTE*>(Singleton<Dx2ShaderAndLayoutManager>::Instance()->GetShader("opaquePS")->GetBufferPointer()),
        Singleton<Dx2ShaderAndLayoutManager>::Instance()->GetShader("opaquePS")->GetBufferSize()
    };
	
    opaquePsoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
    opaquePsoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
    opaquePsoDesc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
    opaquePsoDesc.SampleMask = UINT_MAX;
    opaquePsoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
    opaquePsoDesc.NumRenderTargets = 1;
    opaquePsoDesc.RTVFormats[0] = BackBufferFormat;
    opaquePsoDesc.SampleDesc.Count = _4xMsaaState? 4:1;
    opaquePsoDesc.SampleDesc.Quality = _4xMsaaState? (_4xMsaaQuality - 1):0;
    opaquePsoDesc.DSVFormat = DepthStencilFormat;
	
    ThrowIfFailed(device->CreateGraphicsPipelineState(&opaquePsoDesc,IID_PPV_ARGS(&mPso)));
}

void BasePass::Draw(
        ID3D12GraphicsCommandList* cmdList,
        CD3DX12_GPU_DESCRIPTOR_HANDLE hGpuHandler,
        UINT srvHeapSize,
        UINT objCBByteSize,
        UINT matCBByteSize,
        UINT passCBByteSize,
        ID3D12Resource* objectCB,
        ID3D12Resource* matCB,
        ID3D12Resource* passCB,
        const PassConstants& passValue,
        ID3D12Resource* OutColorRenderTarget,
        D3D12_CPU_DESCRIPTOR_HANDLE OutColorRenderTargetView,
        D3D12_CPU_DESCRIPTOR_HANDLE OutDepthStentilView
        )
{

    cmdList->ClearRenderTargetView(OutColorRenderTargetView,(float*)&passValue.FogColor,0,nullptr);
    cmdList->ClearDepthStencilView(OutDepthStentilView,D3D12_CLEAR_FLAG_DEPTH| D3D12_CLEAR_FLAG_STENCIL,1,0,0,nullptr);

    auto colorBufferView = OutColorRenderTargetView;
    auto depthStencilBufferView = OutDepthStentilView;
    cmdList->OMSetRenderTargets(1,&colorBufferView,true,&depthStencilBufferView);
    
    cmdList->SetPipelineState(mPso.Get());
    cmdList->SetGraphicsRootSignature(Singleton<Dx2RootSignatureManager>::Instance()->GetRootSignature(RootSignatureType::Default).Get());
    cmdList->SetGraphicsRootConstantBufferView(2,passCB->GetGPUVirtualAddress());
    cmdList->SetGraphicsRootDescriptorTable(4, mWaves->DisplacementMap());
    
    DrawRenderItem(cmdList,hGpuHandler,srvHeapSize,objCBByteSize,matCBByteSize,objectCB,matCB,mRenderItems);
    
    for(auto subPass : mSubPass)
    {
        assert(subPass  != nullptr);
        subPass->Draw(cmdList,hGpuHandler,
            srvHeapSize,objCBByteSize,matCBByteSize,passCBByteSize,
            objectCB,matCB,passCB,passValue,
            OutColorRenderTarget,OutColorRenderTargetView,OutDepthStentilView);
    }
}

void BasePass::SetCSWave(std::shared_ptr<GPUWaves> wave)
{
    mWaves = wave;
}

